﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace GGJ.Sprites
{
    public enum FliesMovement
    {
        None = 0,
        Up,
        Down,
        Dead,
        Stuck,
        Swatted,
        Intoxicated
    }

    public class Flies
    {
        private FliesMovement movement = FliesMovement.None;

        private Texture2D flySprites;

        private int tileSize = 64;

        private int spaceBetweenFlies = -16;

        private int x, y;

        private SortedList<int, Fly> flies;

        private double timeSinceLastChangeIdealPosition = 0.0;

        private bool isForcedToGoDown = false;

        public Flies(Texture2D flySprites, int xFirstFly, int yFirstFly)
        {
            x = xFirstFly;
            y = yFirstFly;

            this.flySprites = flySprites;

            flies = new SortedList<int, Fly>();
            flies.Add(0, new Fly(flySprites, xFirstFly, yFirstFly, false));
        }

        public int Count()
        {
            return flies.Count;
        }

        public void setIsForcedToGoDown(bool isForcedToGoDown)
        {
            this.isForcedToGoDown = isForcedToGoDown;
        }

        public bool IsForcedToGoDown()
        {
            return isForcedToGoDown;
        }

        public int getRealCount()
        {
            int nb = 0;
            for (int i = 0; i < flies.Count; i++)
            {
                if (flies[i] != null)
                    nb++;
            }

            return nb;
        }

        public Fly GetFly(int index)
        {
            return flies[index];
        }


        public void SetMovement(FliesMovement newMovement)
        {
            movement = newMovement;
        }

        public void removeFly(int i)
        {
            flies[i] = null;
        }

        public void AddFly()
        {
            bool isFlyPlaced = false;

            double nbseg = 8;

            for (int i = 0; i < flies.Count; i++)
            {
                if (flies[i] == null)
                {
                    nbseg = 8 * ((i - 1) / ((Math.Log(i) + 1) * 8) + 1);

                    double pas = 2 * Math.PI / nbseg;

                    double angle = (i % nbseg - 1) * pas;

                    double radius = (spaceBetweenFlies + tileSize) * ((i - 1) / nbseg + 1);

                    flies[i] = new Fly(flySprites, (int) (x + radius * Math.Cos(angle)), (int) (y + radius * Math.Sin(angle)), false);

                    isFlyPlaced = true;

                    break;
                }
            }

            if (!isFlyPlaced)
            {
                int i = flies.Count;

                //nbseg = 8 * ((i - 1) / 8 + 1);

                nbseg = 8 * ((i - 1) / ((Math.Log(i) + 1) * 8) + 1);

                double pas = 2 * Math.PI / nbseg;

                double angle = (i % nbseg - 1) * pas;

                double radius = (spaceBetweenFlies + tileSize) * ((i-1) / nbseg + 1);

                flies.Add(i, new Fly(flySprites, (int)(x + radius * Math.Cos(angle)), (int)(y + radius * Math.Sin(angle)), false));
            }
        }

        public void AddFly(Fly fly)
        {
            bool isFlyPlaced = false;

            double nbseg = 8;

            if ((flies.Count > 0) && (flies[0] == null))
            {
                flies[0] = new Fly(flySprites, fly.GetDestination().X, fly.GetDestination().Y, false);

                flies[0].setIdealXY(x, y);

                isFlyPlaced = true;
            }
            else
            {
                for (int i = 1; i < flies.Count; i++)
                {
                    if (flies[i] == null)
                    {
                        nbseg = 8 * ((i - 1) / ((Math.Log(i) + 1) * 8) + 1);

                        double pas = 2 * Math.PI / nbseg;

                        double angle = (i % nbseg - 1) * pas;

                        double radius = (spaceBetweenFlies + tileSize) * ((i - 1) / nbseg + 1);

                        flies[i] = new Fly(flySprites, fly.GetDestination().X, fly.GetDestination().Y, false);

                        flies[i].setIdealXY((int)(x + radius * Math.Cos(angle)), (int)(y + radius * Math.Sin(angle)));

                        if (flies[i].isIdealInGame())
                        {
                            isFlyPlaced = true;
                            break;
                        }
                        else
                        {
                            flies[i] = null;
                        }
                    }
                }
            }

            if (!isFlyPlaced)
            {
                int i = flies.Count;

                nbseg = 8 * ((i - 1) / ((Math.Log(i) + 1) * 8) + 1);

                double pas = 2 * Math.PI / nbseg;

                double angle = (i % nbseg - 1) * pas;

                double radius = (spaceBetweenFlies + tileSize) * ((i - 1) / nbseg + 1);

                fly.setIdealXY((int)(x + radius * Math.Cos(angle)), (int)(y + radius * Math.Sin(angle)));

                flies.Add(i, fly);
            }
        }

        public void changeFlyIdealPosition(Fly fly, int flyPosition)
        {
            bool isFlyPlaced = false;

            double nbseg = 8;

            if ((flies.Count > 0) && (flies[0] == null))
            {
                flies[0] = new Fly(flySprites, fly.GetDestination().X, fly.GetDestination().Y, false);

                flies[0].setIdealXY(x, y);

                isFlyPlaced = true;
            }
            else
            {
                for (int i = 1; i < flyPosition; i++)
                {
                    if (flies[i] == null)
                    {
                        nbseg = 8 * ((i - 1) / ((Math.Log(i) + 1) * 8) + 1);

                        double pas = 2 * Math.PI / nbseg;

                        double angle = (i % nbseg - 1) * pas;

                        double radius = (spaceBetweenFlies + tileSize) * ((i - 1) / nbseg + 1);

                        flies[i] = new Fly(flySprites, fly.GetDestination().X, fly.GetDestination().Y, false);

                        flies[i].setIdealXY((int)(x + radius * Math.Cos(angle)), (int)(y + radius * Math.Sin(angle)));

                        if (flies[i].isIdealInGame())
                        {
                            isFlyPlaced = true;
                            break;
                        }
                        else
                        {
                            flies[i] = null;
                        }
                    }
                }
            }

            if (isFlyPlaced)
            {
                removeFly(flyPosition);
            }
        }

        public void Update(GameTime gameTime, bool isSlowMotion)
        {
            bool canMove = true;

            float realSpeed = Program.speedFlies;

            if (isSlowMotion)
                realSpeed = realSpeed / 2;

            if (isForcedToGoDown)
            {
                if (movement == FliesMovement.None)
                    movement = FliesMovement.Down;
                else
                    movement = FliesMovement.None;
            }

            timeSinceLastChangeIdealPosition += gameTime.ElapsedGameTime.TotalSeconds;
            if (timeSinceLastChangeIdealPosition >= 1.0f)
            {
                timeSinceLastChangeIdealPosition -= 1.0f;
                for (int i = 1; i < flies.Count; i++)
                {
                    if (flies[i] != null)
                    {
                        changeFlyIdealPosition(flies[i], i);
                    }
                }
            }

            for (int i = 0; i < flies.Count; i++)
            {
                if (flies[i] != null)
                {
                    if (!flies[i].CanMove(movement, realSpeed))
                    {
                        canMove = false;
                        break;
                    }
                }
            }

            if (canMove)
            {
                if (movement == FliesMovement.Up)
                {
                    y -= (int)realSpeed;
                }
                else if (movement == FliesMovement.Down)
                {
                    y += (int)realSpeed;
                }
            }

            for (int i = 0; i < flies.Count; i++)
            {
                if (flies[i] != null)
                {
                    if (canMove)
                    {
                        flies[i].Update(gameTime, movement, realSpeed, isSlowMotion);
                    }
                    else
                    {
                        flies[i].Update(gameTime, FliesMovement.None, realSpeed, isSlowMotion);
                    }
                }
            }
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            for (int i = 0; i < flies.Count; i++)
            {
                if (flies[i] != null)
                {
                    flies[i].Draw(spriteBatch, (i == 0?Fly.type.general:Fly.type.soldier));
                }
                   
            }
        }
    }
}
